package com.springsecurity.springsecuritydemo.config;

import com.springsecurity.springsecuritydemo.handle.MyAccessDeniedHandler;
import com.springsecurity.springsecuritydemo.handle.MyAuthenticationFailureHandler;
import com.springsecurity.springsecuritydemo.handle.MyAuthenticationSuccessHandler;
import com.springsecurity.springsecuritydemo.service.UserDetailsServiceImpl;
import com.sun.org.apache.xpath.internal.operations.And;
import jdk.nashorn.internal.runtime.regexp.joni.Regex;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

/**
 * Spring Security 配置类
 *
 * @author wangning
 * @create 2021-03-28 13:32
 */
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	private UserDetailsServiceImpl userDetailsService;

	@Autowired
	private MyAccessDeniedHandler myAccessDeniedHandler;

	@Autowired
	private DataSource dataSource;

	@Autowired
	private PersistentTokenRepository persistentTokenRepository;

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.formLogin()    //表单提交
//				.usernameParameter("username123") //自定义账户名
//				.passwordParameter("password123")//自定义密码参数名
				.loginProcessingUrl("/login")    //当发现/login时认为是登陆，必须和表单提交地址一样
//				.loginPage("/login.html")    //自定义登录页面
				.loginPage("/showLogin")
				.successForwardUrl("/toMain") //登录成功后跳转页面，post请求
//				登陆成功处理器，不能和successForwardUrl共存，否则会报错
//				.successHandler(new MyAuthenticationSuccessHandler("/main.html"))
				.failureForwardUrl("/toError");
//				.failureHandler(new MyAuthenticationFailureHandler("/error.html"));
		//授权认证
		http.authorizeRequests()
				//login.html放行
				.antMatchers("/showLogin").permitAll()

//				.antMatchers("/login.html").permitAll()
//				.antMatchers("/error.html").permitAll()
				.antMatchers("/error.html").access("permitAll()")
//				.antMatchers("/js/**", "css/**", "image/**").permitAll()
//				.antMatchers("/**/*.png").permitAll() //所有后缀是.png的都会放行
//				.regexMatchers(".+[.]png").permitAll() //任何目录下的png都会被访问
				//所有的请求必须被认证，必须登录后访问
//				.regexMatchers(HttpMethod.POST, "/demo").permitAll()//放行/demo，并且必须是post请求，如果不是post请求，还会被拦截
//				.mvcMatchers("/demo").servletPath("/xxx").permitAll()//当有一个总的servlet-path，需要配置
//				.antMatchers("/xxx/demo").permitAll() //等效于mvcMatchers
//				.antMatchers("/main1.html").hasAuthority("admin")
//				.antMatchers("/main1.html").hasAnyAuthority("admin", "admin1")
//				.antMatchers("/main1.html").hasRole("ROLEabc")
//				.antMatchers("/main1.html").hasRole("abc")
//				.antMatchers("/main1.html").hasAnyRole("qwer", "abc")//通过角色控制
//				.antMatchers("/main1.html").hasIpAddress("127.0.0.1")//通过ip进行访问控制
				.anyRequest().authenticated();
//				.anyRequest().access("@myServiceImpl.hasPermission(request,authentication)");//自定义权限
		//关闭csrf防护
//		http.csrf().disable();


		http.exceptionHandling()
				.accessDeniedHandler(myAccessDeniedHandler);//异常处理方案

		//记住我,默认的失效时间为两周
		http.rememberMe()
				.tokenValiditySeconds(60)
//				.rememberMeParameter("")
				//自定义登录逻辑
				.userDetailsService(userDetailsService)
				//持久层对象
				.tokenRepository(persistentTokenRepository);

		http.logout()
				.logoutUrl("/user/logout")//自定义退出
				.logoutSuccessUrl("/login.html");//自定义退出成功后跳转
	}

	@Bean
	public PersistentTokenRepository getPersistentTokenRepository() {
		JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
		jdbcTokenRepository.setDataSource(dataSource);
		//自动建表，第一次启动需要，第二次注释掉
//		jdbcTokenRepository.setCreateTableOnStartup(true);
		return jdbcTokenRepository;
	}

	/**
	 * 密码的加密方式
	 *
	 * @return
	 */
	@Bean
	public PasswordEncoder getPasswordEncoder() {
		return new BCryptPasswordEncoder();
	}


}
